<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Chapter&nbsp;7.&nbsp;持久化</title>
    <link rel="stylesheet" href="css/html.css" type="text/css">
    <meta name="generator" content="DocBook XSL Stylesheets V1.65.1">
    <link rel="home" href="index.html" title="JBoss jBPM 3.1">
    <link rel="up" href="index.html" title="JBoss jBPM 3.1">
    <link rel="previous" href="configuration.html" title="Chapter&nbsp;6.&nbsp;Configuration">
    <link rel="next" href="thejbpmdatabase.html" title="Chapter&nbsp;8.&nbsp;The jBPM Database">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
    <table width="100%" summary="Navigation header">
        <tr>
            <th colspan="3" align="center">Chapter&nbsp;7.&nbsp;持久化</th>
        </tr>
        <tr>
            <td width="20%" align="left"><a accesskey="p" href="configuration.html">Prev</a>&nbsp;</td>
            <th width="60%" align="center">&nbsp;</th>
            <td width="20%" align="right">&nbsp;<a accesskey="n" href="thejbpmdatabase.html">Next</a></td>
        </tr>
    </table>
    <hr>
</div>
<div class="chapter" lang="cn">
<div class="titlepage">
    <div>
        <div><h2 class="title"><a name="persistence"></a>Chapter&nbsp;7.&nbsp;持久化</h2></div>
    </div>
    <div></div>
</div>
<p>In most scenarios, jBPM is used to maintain execution of processes that
    span a long time. In this context, "a long time" means spanning several
    transactions. The main purpose of persistence is to store process executions
    during wait states. So think of the process executions as state machines.
    In one transaction, we want to move the process execution state machine from
    one state to the next.
</p>

<p>A process definition can be represented in 3 different forms : as xml, as
    java objects and as records in the jBPM database. Executional (=runtime)
    information and logging information can be represented in 2 forms : as
    java objects and as records in the jBPM database.
</p>

<div class="figure"><a name="model.transformations.image"></a>

    <div class="mediaobject" align="center"><img src="images/model.transformations.jpg" align="middle"
                                                 alt="The transformations and different forms"></div>
    <p class="title"><b>Figure&nbsp;7.1.&nbsp;The transformations and different forms</b></p></div>
<p>For more information about the xml representation of process definitions
    and process archives, see <a href="jpdl.html" title="Chapter&nbsp;16.&nbsp;jBPM Process Definition Language (JPDL)">Chapter&nbsp;16,
    <i>jBPM Process Definition Language (JPDL)</i></a>.</p>

<p>More information on how to deploy a process archive to the database
    can be found in <a href="jpdl.html#deployingaprocessarchive" title="16.1.1.&nbsp;Deploying a process archive">Section&nbsp;16.1.1,
    &#8220;Deploying a process archive&#8221;</a></p>

<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="d0e1973"></a>7.1.&nbsp;持久化 API</h2></div>
        </div>
        <div></div>
    </div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="relationtotheconfigurationframework"></a>7.1.1.&nbsp;Relation to the
                    configuration framework</h3></div>
            </div>
            <div></div>
        </div>
        <p>The persistence API is an integrated with the <a href="configuration.html"
                                                            title="Chapter&nbsp;6.&nbsp;Configuration">
            configuration framework</a> my exposing some convenience persistence methods
            on the JbpmContext. Persistence API operations can therefor be
            called inside a jBPM context block like this:
        </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {

  // Invoke persistence operations here

} finally {
  jbpmContext.close();
}</pre>
        <p>In what follows, we suppose that the configuration includes a persistence
            service similar to this one (as in the example configuration file
            <tt class="literal">src/config.files/jbpm.cfg.xml</tt>):
        </p><pre class="programlisting">&lt;jbpm-configuration&gt;

  &lt;jbpm-context&gt;
    &lt;service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' /&gt;
    ...
  &lt;/jbpm-context&gt;
  ...
&lt;/jbpm-configuration&gt;</pre>
    </div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="conveniencemethodsonjbpmcontext"></a>7.1.2.&nbsp;Convenience methods on
                    JbpmContext</h3></div>
            </div>
            <div></div>
        </div>
        <p>The three most common persistence operations are:
        </p>

        <div class="itemizedlist">
            <ul type="disc">
                <li>Deploying a process</li>
                <li>Starting a new execution of a process</li>
                <li>Continuing an execution</li>
            </ul>
        </div>
        <p>
        </p>

        <p>First deploying a process definition. Typically, this will be done directly
            from the graphical process designer or from the deployprocess ant task. But here
            you can see how this is done programmatically:
        </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  ProcessDefinition processDefinition = ...;
  jbpmContext.deployProcessDefinition(processDefinition);
} finally {
  jbpmContext.close();
}</pre>
        <p>For the creation of a new process execution, we need to specify of which process
            definition this execution will be an instance. The most common way to specify this
            is to refer to the name of the process and let jBPM find the latest version of that
            process in the database:
        </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  String processName = ...;
  ProcessInstance processInstance = 
      jbpmContext.newProcessInstance(processName);
} finally {
  jbpmContext.close();
}</pre>
        <p>For continuing a process execution, we need to fetch the process instance, the
            token or the taskInstance from the database, invoke some methods on the POJO jBPM
            objects and afterwards save the updates made to the processInstance into the database
            again.
        </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long processInstanceId = ...;
  ProcessInstance processInstance = 
      jbpmContext.loadProcessInstance(processInstanceId);
  processInstance.signal();
  jbpmContext.save(processInstance);
} finally {
  jbpmContext.close();
}</pre>
        <p>Note that if you use the xxx<span class="bold"><b>ForUpdate</b></span> methods in
            the JbpmContext, an explicit invocation of the jbpmContext.save is not necessary any
            more because it will then occur automatically during the close of the jbpmContext.
            E.g. suppose we want to inform jBPM about a taskInstance that has been completed.
            Note that task instance completion can trigger execution to continue so the
            processInstance related to the taskInstance must be saved. The most convenient way
            to do this is to use the loadTaskInstanceForUpdate method:
        </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long taskInstanceId = ...;
  TaskInstance taskInstance = 
      jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
  taskInstance.end();
} finally {
  jbpmContext.close();
}</pre>
        <p>Just as background information, the next part is an explanation of how jBPM manages
            the persistence and uses hibernate.
        </p>

        <p>The <tt class="literal">JbpmConfiguration</tt> maintains a set of
            <tt class="literal">ServiceFactory</tt>s. The service factories are configured in the
            <tt class="literal">jbpm.cfg.xml</tt> as shown above and instantiated lazy. The
            <tt class="literal">DbPersistenceServiceFactory</tt> is only instantiated the first time
            when it is needed. After that, service factories are maintained in the
            <tt class="literal">JbpmConfiguration</tt>. A <tt class="literal">DbPersistenceServiceFactory</tt>
            manages a hibernate <tt class="literal">SessionFactory</tt>. But also the hibernate
            session factory is created lazy when requested the first time.
        </p>

        <div class="figure"><a name="persistence.api.image"></a>

            <div class="mediaobject" align="center"><img src="images/persistence.api.gif" align="middle"
                                                         alt="The persistence related classes"></div>
            <p class="title"><b>Figure&nbsp;7.2.&nbsp;The persistence related classes</b></p></div>
        <p>During the invocation of <tt class="literal">jbpmConfiguration.createJbpmContext()</tt>,
            only the <tt class="literal">JbpmContext</tt> is created. No further persistence related
            initializations are done at that time. The <tt class="literal">JbpmContext</tt> manages
            a <tt class="literal">DbPersistenceService</tt>, which is instantiated upon first request.
            The <tt class="literal">DbPersistenceService</tt> manages the hibernate session. Also the
            hibernate session inside the <tt class="literal">DbPersistenceService</tt> is created lazy.
            As a result, a hibernate session will be only be opened when the first operation is
            invoked that requires persistence and not earlier.
        </p></div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="advancedapiusage"></a>7.1.3.&nbsp;Advanced API usage</h3></div>
            </div>
            <div></div>
        </div>
        <p>The DbPersistenceService maintains a lazy initialized hibernate session. All
            database access is done through this hibernate session. All queries and updates
            done by jBPM are exposed by the XxxSession classes like e.g. GraphSession,
            SchedulerSession, LoggingSession,... These session classes refer to the hibernate
            queries and all use the same hibernate session underneath.
        </p>

        <p>The XxxxSession classes are accessible via the JbpmContext as well.
        </p></div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="configurationthepersistenceservice"></a>7.2.&nbsp;配置持久化服务</h2></div>
        </div>
        <div></div>
    </div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="thehibernatesessionfactory"></a>7.2.1.&nbsp;The hibernate session
                    factory</h3></div>
            </div>
            <div></div>
        </div>
        <p>By default, the DbPersistenceServiceFactory will use the resource hibernate.cfg.xml
            in the root of the classpath to create the hibernate session factory. Note that the
            hibernate configuration file resource is mapped in the property 'jbpm.hibernate.cfg.xml'
            and can be customized in the jbpm.cfg.xml. This is the default configuration:
        </p><pre class="programlisting">&lt;jbpm-configuration&gt;
  ...
  &lt;!-- configuration resource files pointing to default configuration files in jbpm-{version}.jar --&gt;
  &lt;string name='resource.hibernate.cfg.xml' 
          value='hibernate.cfg.xml' /&gt;
  &lt;!-- &lt;string name='resource.hibernate.properties' 
                  value='hibernate.properties' /&gt; --&gt;
  ...
&lt;/jbpm-configuration&gt;</pre>
        <p>When the property <span class="bold"><b>resource.hibernate.properties</b></span>
            is specified, the properties in that resource file will <span class="bold"><b>overwrite
            all</b></span> the properties in the hibernate.cfg.xml. Instead of updating the hibernate.cfg.xml to
            point to your DB, the hibernate.properties can be used to handle jbpm upgrades conveniently:
            The hibernate.cfg.xml can then be copied without having to reapply the changes.
        </p></div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="thedbpersistenceservicefactory"></a>7.2.2.&nbsp;The
                    DbPersistenceServiceFactory</h3></div>
            </div>
            <div></div>
        </div>
        <p>The DbPersistenceServiceFactory itself has 3 more configuration properties: isTransactionEnabled,
            sessionFactoryJndiName and dataSourceJndiName. To specify any of these properties in the jbpm.cfg.xml,
            you need to specify the service factory as a bean in the factory element like this:
        </p><pre class="programlisting">  &lt;jbpm-context&gt;
    &lt;service name="persistence"&gt;
      &lt;factory&gt;
        &lt;bean factory="org.jbpm.persistence.db.DbPersistenceServiceFactory"&gt;
          &lt;field name="isTransactionEnabled"&gt;&lt;false /&gt;&lt;/field&gt;
          &lt;field name="sessionFactoryJndiName"&gt;
            &lt;string value="java:/myHibSessFactJndiName" /&gt;
          &lt;/field&gt;
          &lt;field name="dataSourceJndiName"&gt;
            &lt;string value="java:/myDataSourceJndiName" /&gt;
          &lt;/field&gt;
        &lt;/bean&gt;
      &lt;/factory&gt;
    &lt;/service&gt;
    ...
  &lt;/jbpm-context&gt;</pre>
        <div class="itemizedlist">
            <ul type="disc">
                <li><span class="bold"><b>isTransactionEnabled</b></span>: by default, jBPM will
                    begin and end hibernate transactions. To disable transactions and prohibit jBPM
                    from managing transactions with hibernate, configure the isTransactionEnabled property
                    to false as in the example above. For more info about transactions, see
                    <a href="persistence.html#hibernatetransactions" title="7.3.&nbsp;Hibernate transactions">Section&nbsp;7.3,
                        &#8220;Hibernate 事务&#8221;</a>.
                </li>
                <li><span class="bold"><b>sessionFactoryJndiName</b></span>: by default, this
                    is null, meaning that the session factory is not fetched from JNDI. If set and
                    a session factory is needed to create a hibernate session, the session factory
                    will be fetched from jndi using the provided JNDI name.
                </li>
                <li><span class="bold"><b>dataSourceJndiName</b></span>: by default, this is
                    null and creation of JDBC connections will be delegated to hibernate. By specifying
                    a datasource, jBPM will fetch a JDBC connection from the datasource and provide that
                    to hibernate while opening a new session. For user provided JDBC connections,
                    see <a href="persistence.html#userprovidedstuff" title="7.5.&nbsp;User provided stuff">Section&nbsp;7.5,
                    &#8220;用户提供的东西&#8221;</a>.
                </li>
            </ul>
        </div>
    </div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="hibernatetransactions"></a>7.3.&nbsp;Hibernate
                事务</h2></div>
        </div>
        <div></div>
    </div>
    <p>By default, jBPM will delegate transaction to hibernate and use the session per transaction
        pattern. jBPM will begin a hibernate transaction when a hibernate session is opened.
        This will happen the first time when a persistent operation is invoked on the jbpmContext.
        The transaction will be committed right before the hibernate session is closed. That
        will happen inside the jbpmContext.close().
    </p>

    <p>Use <tt class="literal">jbpmContext.setRollbackOnly()</tt> to mark a transaction for rollback.
        In that case, the transaction will be rolled back right before the session is closed
        inside of the jbpmContext.close().
    </p>

    <p>To prohibit jBPM from invoking any of the transaction methods on the hibernate
        API, set the isTransactionEnabled property to false as explained in <a
            href="persistence.html#thedbpersistenceservicefactory" title="7.2.2.&nbsp;The DbPersistenceServiceFactory">Section&nbsp;7.2.2,
        &#8220;The DbPersistenceServiceFactory&#8221;</a>
        above.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="managedtransactions"></a>7.4.&nbsp;管理事务
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>The most common scenario for managed transactions is when using jBPM in a JEE application
        server like JBoss. The most common scenario is the following:
    </p>

    <div class="itemizedlist">
        <ul type="disc">
            <li>configure a DataSource in your application server
            </li>
            <li>configure hibernate to use that data source for its connections
            </li>
            <li>use container managed transactions
            </li>
            <li>disable transactions in jBPM
            </li>
        </ul>
    </div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="userprovidedstuff"></a>7.5.&nbsp;用户提供的东西
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>You can also programmatically provide JDBC connections, hibernate sessions and
        hibernate session factories to jBPM.
    </p>

    <p>When such a resource is provided to jBPM, it will use the provided resources
        rather then the configured ones.
    </p>

    <p>The <tt class="literal">JbpmContext</tt> class contains some convenience methods to
        inject resources programmatically. For example, to provide a JDBC connectio to
        jBPM, use the following code:
    </p><pre class="programlisting">JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  Connection connection = ...;
  jbpmContext.setConnection(connection);
  
  // invoke one or more persistence operations

} finally {
  jbpmContext.close();
}</pre>
    <p>the JbpmContext class has following convenience methods for providing resource
        programmatically:
    </p><pre class="programlisting">JbpmContext.setConnection(Connection);
JbpmContext.setSession(Session);
JbpmContext.setSessionFactory(SessionFactory);
</pre>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="customizingqueries"></a>7.6.&nbsp;定制查询
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>All the HQL queries that jBPM uses are centralized in one configuration file.
        That resource file is referenced in the hibernate.cfg.xml configuration file
        like this:
    </p><pre class="programlisting">&lt;hibernate-configuration&gt;
  ...
    &lt;!-- hql queries and type defs --&gt;
    &lt;mapping resource="org/jbpm/db/hibernate.queries.hbm.xml" /&gt;
  ...
&lt;/hibernate-configuration&gt;</pre>
    <p>To customize one or more of those queries, take a copy of the original file
        and put your customized version somewhere on the classpath. Then update the
        reference 'org/jbpm/db/hibernate.queries.hbm.xml' in the hibernate.cfg.xml to point to your
        customized version.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="databasecompatibility"></a>7.7.&nbsp;数据库兼容性</h2></div>
        </div>
        <div></div>
    </div>
    <p>jBPM runs on any database that is supported by hibernate.
    </p>

    <p>The example configuration files in jBPM (<tt class="literal">src/config.files</tt>) specify
        the use of the hypersonic in-memory database. That database is ideal during development and
        for testing. The hypersonic in-memory database keeps all its data in memory and doesn't
        store it on disk.
    </p>

    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="changingthejbpmdb"></a>7.7.1.&nbsp;Changing the jBPM DB</h3></div>
            </div>
            <div></div>
        </div>
        <p>Following is an indicative list of things to do when changing jBPM to
            use a different database:
        </p>

        <div class="itemizedlist">
            <ul type="disc">
                <li>put the jdbc-driver library archive in the classpath
                </li>
                <li>update the hibernate configuration used by jBPM
                </li>
                <li>create the schema in the new database
                </li>
            </ul>
        </div>
    </div>
    <div class="section" lang="cn">
        <div class="titlepage">
            <div>
                <div><h3 class="title"><a name="thejbpmdbschema"></a>7.7.2.&nbsp;The jBPM DB schema</h3></div>
            </div>
            <div></div>
        </div>
        <p>The jbpm.db subproject, contains a number of drivers, instructions and
            scripts to help you getting started on your database of choice. Please,
            refer to the readme.html in the root of the jbpm.db project for more
            information.
        </p>

        <p>While jBPM is capable of generating DDL scripts for all database, these
            schemas are not always optimized. So you might want to have your DBA review
            the DDL that is generated to optimize the column types and use of indexes.
        </p>

        <p>In development you might be interested in the following hibernate configuration:
            If you set hibernate configuration property 'hibernate.hbm2ddl.auto' to 'create-drop'
            (e.g. in the hibernate.cfg.xml), the schema will be automatically created in the
            database the first time it is used in an application. When the application closes
            down, the schema will be dropped.
        </p>

        <p>The schema generation can also be invoked programmatically with
            <tt class="literal">jbpmConfiguration.createSchema()</tt> and
            <tt class="literal">jbpmConfiguration.dropSchema()</tt>.
        </p></div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="d0e2219"></a>7.8.&nbsp;结合你的 hibernate 类
            </h2></div>
        </div>
        <div></div>
    </div>
    <p>In your project, you might use hibernate for your persistence. Combining your
        persistent classes with the jBPM persistent classes is optional. There are two major
        benefits when combining your hibernate persistence with jBPM's hibernate persistence:
    </p>

    <p>First, session, connection and transaction management become easier. By combining
        jBPM and your persistence into one hibernate session factory,
        there is one hibernate session, one jdbc connection that handles both yours and
        jBPM's persistence. So automatically the jBPM updates are in the same transaction
        as the updates to your own domain model. This can eliminates the need for using
        a transaction manager.
    </p>

    <p>Secondly, this enable you to drop your hibernatable persistent object in to the
        process variables without any further hassle.
    </p>

    <p>The easiest way
        to integrate your persistent classes with the jBPM persistent classes is by
        creating one central hibernate.cfg.xml. You can take the jBPM
        <tt class="literal">src/config.files/hibernate.cfg.xml</tt> as a starting point and
        add references to your own hibernate mapping files in there.
    </p></div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="d0e2233"></a>7.9.&nbsp;定制 jBPM的 hibernate
                映射文件</h2></div>
        </div>
        <div></div>
    </div>
    <p>To customize any of the jBPM hibernate mapping files, you can proceed as
        follows:
    </p>

    <div class="itemizedlist">
        <ul type="disc">
            <li>copy the jBPM hibernate mapping file(s) you want to copy from the
                sources (<tt class="literal">src/java.jbpm/...</tt>) or from inside of the
                jbpm jar.
            </li>
            <li>
                put the copy anywhere you want on the classpath
            </li>
            <li>
                update the references to the customized mapping files in the hibernate.cfg.xml
                configuration file
            </li>
        </ul>
    </div>
</div>
<div class="section" lang="cn">
    <div class="titlepage">
        <div>
            <div><h2 class="title" style="clear: both"><a name="secondlevelcache"></a>7.10.&nbsp;二级缓存</h2>
            </div>
        </div>
        <div></div>
    </div>
    <p>jBPM uses hibernate's second level cache for keeping the process definitions
        in memory after loading them once. The process definition classes and collections
        are configured in the jBPM hibernate mapping files with the cache element like this:
    </p>
    <pre class="programlisting">&lt;cache usage="nonstrict-read-write"/&gt;</pre>
    <p>Since process definitions (should) never change, it is ok to keep them in the
        second level cache. See also <a href="jpdl.html#changingdeployedprocessdefinitions"
                                        title="16.1.3.&nbsp;Changing deployed process definitions">Section&nbsp;16.1.3,
        &#8220;Changing deployed process definitions&#8221;</a>.
    </p>

    <p>The second level cache is an important aspect of the JBoss jBPM implementation.
        If it weren't for this cache, JBoss jBPM could have a serious drawback in comparison
        to the other techniques to implement a BPM engine.
    </p>

    <p>The caching strategy is set to <tt class="literal">nonstrict-read-write</tt>. At
        runtime, the caching strategy could be set to <tt class="literal">read-only</tt>. But in
        that case, you would need a separate set of hibernate mapping files for
        deploying a process. That is why we opted for the nonstrict-read-write.
    </p></div>
</div>
<div class="navfooter">
    <hr>
    <table width="100%" summary="Navigation footer">
        <tr>
            <td width="40%" align="left"><a accesskey="p" href="configuration.html">Prev</a>&nbsp;</td>
            <td width="20%" align="center"><a accesskey="u" href="index.html">Up</a></td>
            <td width="40%" align="right">&nbsp;<a accesskey="n" href="thejbpmdatabase.html">Next</a></td>
        </tr>
        <tr>
            <td width="40%" align="left" valign="top">Chapter&nbsp;6.&nbsp;Configuration&nbsp;</td>
            <td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
            <td width="40%" align="right" valign="top">&nbsp;Chapter&nbsp;8.&nbsp;The jBPM Database</td>
        </tr>
    </table>
</div>
</body>
</html>